package com.sankuai.project.config;


import com.sankuai.project.dao.SyslogMapper;
import com.sankuai.project.model.Syslog;
import lombok.RequiredArgsConstructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;

@Component
@Aspect
@RequiredArgsConstructor
public class LogAspect {

    // 引入日志配置
    private static final Log LOGGER = LogFactory.getLog(LogAspect.class);

    @Resource
    private final SyslogMapper syslogMapper;

    /**
     * 定义一个切入点，只拦截controller
     * 第一个 * 代表任意修饰符任意返回值
     * 第二个 * 定义web包或者子包
     * 第三个 * 任意方法
     * .. 匹配任意数量的参数
     */
    @Pointcut("execution(* com.sankuai.project.controller..*.*(..)) && @annotation(com.sankuai.project.annotation" +
            ".LogAnnotation)")
    public void logPointcut() {
    }

    // around(和上面方法名一样)
    @Around("logPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Syslog syslog = new Syslog();
        LOGGER.info("========== Method  start ==========");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        long start = System.currentTimeMillis();
        Calendar requestTime = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String reqTime = simpleDateFormat.format(requestTime.getTime());
        LOGGER.info("请求时间: " + reqTime);
        try {
            Object result = joinPoint.proceed();
            long end = System.currentTimeMillis();
            LOGGER.info("请求地址: " + request.getRequestURI());
            LOGGER.info("用户IP: " + request.getRemoteAddr());
            LOGGER.info("请求方法: " + request.getMethod());
            LOGGER.info("CLASS_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            LOGGER.info("参数: " + joinPoint.getArgs()[joinPoint.getArgs().length - 1]);
            LOGGER.info("执行时间: " + (end - start) + "ms!");
            LOGGER.info("========== Method  End ==========\n");

            syslog.setIp(request.getRemoteAddr());
            syslog.setPath(request.getRequestURI());
            syslog.setMethod(request.getMethod());
            syslog.setRespTime((end - start) + "ms");
            syslog.setParam(joinPoint.getArgs()[joinPoint.getArgs().length - 1].toString());
            syslog.setTime(simpleDateFormat.parse(reqTime));
            syslog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            syslogMapper.insert(syslog);
            return result;
        } catch (Throwable e) {
            long end = System.currentTimeMillis();
            LOGGER.info("URL:" + request.getRequestURI());
            LOGGER.info("IP:" + request.getRemoteAddr());
            LOGGER.info("请求方法: " + request.getMethod());
            LOGGER.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            LOGGER.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
            LOGGER.info("执行时间: " + (end - start) + " ms!");
            LOGGER.info("========== Method  End ==========\n");
            syslog.setIp(request.getRemoteAddr());
            syslog.setPath(request.getRequestURI());
            syslog.setMethod(request.getMethod());
            syslog.setRespTime((end - start) + "ms");
            syslog.setParam(joinPoint.getArgs()[joinPoint.getArgs().length - 1].toString());
            syslog.setTime(simpleDateFormat.parse(reqTime));
            syslog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            syslogMapper.insert(syslog);
            throw e;
        }
    }
}
